#!/usr/bin/python3
# -*- coding.utf-8 -*-

from pydantic import BaseModel, ValidationError
from typing import Optional, List, Annotated
from datetime import datetime

"""
    Data validation and settings management using python type annotations.
    使用Python的类型注解来进行数据校验和settings管理

    pydantic enforces type hints at runtime, and provides user friendly errors when data is invalid.
    Pydantic可以在代码运行时提供类型提示，数据校验失败时提供友好的错误提示

    Define how data should be in pure, canonical python; validate it with pydantic.
    定义数据应该如何在纯规范的Python代码中保存，并用Pydantic验证它
"""

# 定义一个用户模型
class User(BaseModel):
    id: int                     # 必填参数
    name: str = "John snow"     # 有默认值的可选参数
    sign_date: Optional[datetime] = None    # 默认为None的可选参数
    friends: List[int] = []     # 存储整数类型的列表，或者可以转换成整数的元素[1, 2]  [1, 2, '3']

john = {
    "id": 1001,
    "name": "Mark",
    "sign_date": datetime.now(),
    "friends": [1, 2, "3"]
}

u1 = User(**john)
print(u1.name)
print(str(u1.sign_date))
print(repr(u1.sign_date))
print(u1.dict)
print('json:', u1.json)


# 还带有校验功能
try:
    u2 = User(
        id = 1002,
        name = 'Jack',
        friends = [1, 2, "a"]
    )
    print(u2.sign_date)
except ValidationError as e:
    print(e.json())

# 可以通过User的方法来实例化验证
u3 = User.model_validate(john)
print('u3', u3.dict)

print('-' * 20)
# 通过原生的字符串转换为对象
print(User.model_validate_json('{"id":101,"name":"大力","singup_date":"2024-12-09 12:20","friends":[1,2,"3"]}'))

print('************************')
# # 不检验数据直接创建模型类，不建议在construct方法中传入未经验证的数据
# user_data = {"id":"abc","name":"大力","singup_date":"2024-12-09 12:20","friends":[1,2,"3"]}
# print(User.construct(**user_data))
# 获取模型的所有字段，保持顺序
print('所有字段：', User.model_fields.keys())

# 模型的嵌套
class Sound(BaseModel):
    sound: str

class Dog(BaseModel):
    name: str
    weight: float = 2.0
    # Dog模型中的sound的类型是另外一个模型Sound
    sound: List[Sound]


dh = Dog(
    name = "大黄",
    weight =3.5,
    sound = [{"sound":"汪汪"}, {"sound":"嘤嘤"}]
)
print(dh.dict)



# 泛型的案例，可以用作数据验证

def validate_numb(n: int) -> bool:
    return n > 0

def process_num(num: Annotated[int, validate_numb]):
    if validate_numb(num):
        print(num)
    else:
        print('非法的参数')

process_num(-10)
